// JHSerialPort.cpp 
//

#include "stdafx.h"
#include "stdlib.h"
#include "JHSerialPort.h"
 

#ifndef _COMM_SERIALPORT_
#define _COMM_SERIALPORT_
typedef struct _COMM_SERIALPORT{
	HANDLE fd;
	JHINFO_SERIALPORT info;
}COMM_SERIALPORT, *LPCOMM_SERIALPORT;
#endif // !_COMM_SERIALPORT


static JHZRESULT JHSerialport_Open (HANDLE * thdl, const void * argstruct)
{
	COMM_SERIALPORT * pthdl;

	if ( NULL == thdl 
		|| NULL == argstruct 
		|| sizeof(JHINFO_SERIALPORT) != (*(unsigned long *)argstruct) )
	{
		return JR_INVALID_PARAMETER;
	}

	pthdl = (COMM_SERIALPORT *)calloc(1, sizeof(COMM_SERIALPORT));
	if(NULL == pthdl)
	{
		return JR_NOT_ENOUGH_CORE;
	}

	pthdl->info = *((LPJHINFO_SERIALPORT)argstruct);

	// Open Com 
	pthdl->fd = CreateFileA(pthdl->info.serialport, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if(INVALID_HANDLE_VALUE == pthdl->fd)
	{
		free(pthdl);
		return JR_OCCUPIED;
	}

	// Set communication buffers
	if (!SetupComm(pthdl->fd, 1280, 1280))
	{
		CloseHandle(pthdl->fd);
		pthdl->fd = NULL;
		free(pthdl);
		return JR_INVALID_OBJECT;
	}

	// Set the serial communications device
	DCB dcb;
	ZeroMemory (&dcb, sizeof(DCB));
	dcb.DCBlength = sizeof(DCB);
	dcb.BaudRate = pthdl->info.baudrate;
	dcb.fBinary = 1;
	dcb.fDtrControl = DTR_CONTROL_DISABLE;
	dcb.fRtsControl = RTS_CONTROL_DISABLE;
	dcb.ByteSize = pthdl->info.databits;
	dcb.Parity = pthdl->info.parity;
	dcb.StopBits = pthdl->info.stopbits;

	if (!SetCommState(pthdl->fd, &dcb))
	{
		CloseHandle(pthdl->fd);
		pthdl->fd = INVALID_HANDLE_VALUE;
		free(pthdl);
		return JR_INVALID_OBJECT;
	}

	// Set the serial communications timeout
	COMMTIMEOUTS ct;
	ZeroMemory (&ct, sizeof(COMMTIMEOUTS));
	ct.ReadIntervalTimeout = pthdl->info.timeout;
	ct.ReadTotalTimeoutMultiplier = pthdl->info.timeout;
	ct.ReadTotalTimeoutConstant = pthdl->info.timeout;

	if (!SetCommTimeouts(pthdl->fd, &ct))
	{
		CloseHandle(pthdl->fd);
		pthdl->fd = INVALID_HANDLE_VALUE;
		free(pthdl);
		return JR_INVALID_OBJECT;
	}

	*thdl = pthdl;

	return JR_OK;
}

static JHZRESULT JHSerialport_Read (HANDLE thdl, unsigned char * buff, unsigned long btr, unsigned long * br)
{
	if ( NULL == thdl 
		|| NULL == buff 
		|| NULL == br )
	{
		return JR_INVALID_PARAMETER;
	}

	COMM_SERIALPORT * pthdl = (COMM_SERIALPORT *)thdl;

	if (!ReadFile(pthdl->fd, buff, 1, br, NULL))
	{
		return JR_TRANSFER_ERR;
	}

	if (*br <= 0)
	{
		return JR_TIMEOUT;
	}

	return JR_OK;
}

static JHZRESULT JHSerialport_Write (HANDLE thdl, const unsigned char * buff, unsigned long btw, unsigned long * bw)
{
	if ( NULL == thdl 
		|| NULL == buff 
		|| NULL == bw )
	{
		return JR_INVALID_PARAMETER;
	}

	COMM_SERIALPORT * pthdl = (COMM_SERIALPORT *)thdl;

	if (!WriteFile(pthdl->fd, (void *)buff, btw, bw, NULL))
	{
		return JR_TRANSFER_ERR;
	}

	if (*bw <= 0)
	{
		return JR_TIMEOUT;
	}

	return JR_OK;
}

static JHZRESULT JHSerialport_Close (HANDLE thdl)
{
	if (NULL == thdl)
	{
		return JR_INVALID_PARAMETER;
	}

	COMM_SERIALPORT * pthdl = (COMM_SERIALPORT *)thdl;

	if (pthdl->fd)
	{
		CloseHandle (pthdl->fd);
		pthdl->fd = INVALID_HANDLE_VALUE;
	}

	if (pthdl)
	{
		free(pthdl);
		pthdl = NULL;
	}

	return JR_OK;
}

JHTRANSPORTLAYER JHTransportlayer_serialport = {
	JHSerialport_Open,
	JHSerialport_Read,
	JHSerialport_Write,
	JHSerialport_Close
};